package com.alpha.processor.processor.anno_processor;

import com.alpha.binder.anno.interfaces.BinderConnector;
import com.alpha.binder.anno.interfaces.ProcessorInterface;
import com.alpha.binder.anno.interfaces.ViewInterface;
import com.alpha.processor.creators.info_model.ConnectorInterfaceInfoModel;
import com.alpha.processor.processor.anno_processor.base.AnnoProcessor;
import com.alpha.processor.processor.tools.AnnoProcessorToolException;
import com.alpha.processor.processor.tools.ProcessorTool;

import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;

public class InterfaceAnnoProcessor extends AnnoProcessor {

    private TypeElement viewElement;
    private TypeElement processorElement;
    private ConnectorInterfaceInfoModel interfaceInfoModel;

    public InterfaceAnnoProcessor(Messager messager, Elements elementUtils, ProcessorTool logger) {
        super(messager, elementUtils, logger);
    }

    @Override
    public void processAnno(RoundEnvironment roundEnvironment) {
        Set<? extends Element> viewSet = roundEnvironment.getElementsAnnotatedWith(ViewInterface.class);
        if (viewSet.size() != 1){
            throw new AnnoProcessorToolException("\n\tError: Need One And Only One <@ViewInterface> Interface;");
        }
        for (Element element : viewSet) {
            this.viewElement = (TypeElement) element;
        }

        Set<? extends Element> processorSet = roundEnvironment.getElementsAnnotatedWith(ProcessorInterface.class);
        if (viewSet.size() != 1){
            throw new AnnoProcessorToolException("\n\tError: Need One And Only One <@ProcessorInterface> Interface;");
        }
        for (Element element : processorSet) {
            this.processorElement = (TypeElement) element;
        }

        Set<? extends Element> connectorSet = roundEnvironment.getElementsAnnotatedWith(BinderConnector.class);
        if (connectorSet.size() != 1){
            throw new AnnoProcessorToolException("\n\tError: Need One And Only One <@BinderConnector> Interface;");
        }
        TypeElement connectorElement = null;
        this.interfaceInfoModel = new ConnectorInterfaceInfoModel();
        for (Element element : connectorSet) {
            connectorElement = (TypeElement) element;
        }
        String superInterfaceName = "com.alpha.binder.interfaces.ConnectorInterface";
        List<? extends TypeMirror> superTypeList = connectorElement.getInterfaces();
        if (superTypeList.size() != 1){
            throw new AnnoProcessorToolException("\n\tError: <@BinderConnector> Interface Can Only Have One SuperClass");
        }
        TypeElement superElement = getElementFromType(superTypeList.get(0));
        if (!superInterfaceName.equals(superElement.getQualifiedName().toString())){
            throw new AnnoProcessorToolException("\n\tError: <@BinderConnector> Interface Can Only Extends <" + superInterfaceName + ">;" + superTypeList.get(0).toString());
        }
        interfaceInfoModel.updateConnectorInterfaceInfo(connectorElement,superTypeList);

        logger.addArgs("View --- " + viewElement.getQualifiedName().toString());
        logger.addArgs("Processor --- " + processorElement.getQualifiedName().toString());
        logger.addArgs("Connector --- " + connectorElement.getQualifiedName().toString());
    }

    public TypeElement getViewElement() {
        return viewElement;
    }

    public TypeElement getProcessorElement() {
        return processorElement;
    }

    public ConnectorInterfaceInfoModel getInterfaceInfoModel() {
        return interfaceInfoModel;
    }
}
